package com.dys.ai.controller;

import com.dys.ai.config.LoggingAdvisor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.time.LocalDate;

@RestController
@CrossOrigin
public class OpenAiController {

    private final ChatClient chatClient;

    public OpenAiController(ChatClient.Builder chatClientBuilder, VectorStore vectorStore, ChatMemory chatMemory) {
        this.chatClient = chatClientBuilder
                .defaultSystem("""
                        您是 [大源数] 航空公司的客户聊天支持代理。请以友好、乐于助人且愉快的方式来回复。
                        您正在通过在线聊天系统与客户互动。
                        在提供有关预订或退订的信息之前，您必须始终
                        从用户处获取以下信息：✅预订号｜✅客户姓名。
                        在询问用户之前，请检查消息历史记录以获取此信息。
                        在修改预订或退订之前，请先获取预订信息并且告知条款待用户回复确定之后才进行修改预订或退订的function-call
                        如果用户想要修改预订信息，请先让用户提供以下信息：✅出发时间｜✅出发地｜✅目的地，用户提供之后，让用户确认一遍，再执行修改的function-call
                        请讲中文。
                        今天的日期是 {current_date}.
                        """)
                // 对话记忆功能
                .defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory),
                        // RAG 空字符串检索所有内容
                        new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults().build()),
                        new LoggingAdvisor())
                .defaultFunctions("cancelBooking", "getBookingDetails", "changeBooking")
                .build();
    }

    @CrossOrigin
    @GetMapping(value = "/ai/generateStreamAsString", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> generateStreamAsString(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {
        Flux<String> content = this.chatClient.prompt()
                .user(message)
                .system(s -> s.param("current_date", LocalDate.now().toString()))
                // .advisors() 检索内容根据对话内容来
                // 配置记忆长度
                .advisors(advisors -> advisors.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
                .stream()
                .content();
        return content.concatWith(Flux.just("[complete]"));
    }
}
